package com.myapi.ModelPoker;
import java.util.*;

import com.myapi.client.DAO.DealerDAO;
import com.myapi.server.PokerServiceImpl;



public abstract class Dealer implements Observer {
	private String id;
	private CardDeck cardDeck;
	private Table table;

	public Dealer(String id) {
		setId(id);
		cardDeck = new CardDeck();
		table = null;
	}	

	public void getOddsPlayer(ArrayList<PlayerHand> playerHands){
		int nbSimulation=10000;
		for(int s=0;s<nbSimulation;s++){
			CardDeck deck = getCardDeck();
			ArrayList<Card> communityCard=new ArrayList<Card>();
			for(int i=0;i<7-playerHands.get(0).cards.size();i++){
				Card cardTmp=deck.getRandomCard();
				while(communityCard.contains(cardTmp)){
					cardTmp=deck.getRandomCard();
				}
				communityCard.add(cardTmp);
				for(int j=0;j<playerHands.size();j++){

					playerHands.get(j).cards.add(cardTmp);

				}
			}
           Object[] listCard=  playerHands.get(0).getCards().toArray();
			Collections.sort(playerHands);
			for(int i=0;i<communityCard.size();i++){
				for(int j=0;j<playerHands.size();j++){
					playerHands.get(j).removeCard(communityCard.get(i));
					
				}
			}
			communityCard.removeAll(communityCard);
		
			playerHands.get(0).setOdds(playerHands.get(0).getOdds()+1);
			
		}
		for(int i=0;i<playerHands.size();i++){
			playerHands.get(i).setOdds(100*playerHands.get(i).getOdds()/(double)nbSimulation);
		}


	}
	public void startHand(double ante, double smallBlind, double bigBlind) {
		PokerServiceImpl pokerServerControler = PokerServiceImpl.getpokerServerControler();
		prepareDeck();
		setPlayerHandMucks(false);
		getTable().setCurrentBet(bigBlind);
		if(ante > 0)
			getAntes(ante);
		if(bigBlind > 0)
			getBlinds(smallBlind, bigBlind);
		dealToHands(5);  //default: deals 5 cards to each hand
		pokerServerControler.startPreflop();
	}

	public void endHand() {
		Table table = getTable();
		determineWinners();
		setPlayerHandMucks(true);
		table.incrementButton();
		table.clearPots();
		table.gameRunning=false;
	}
	/**
	 * Creates a new card deck
	 */
	public void prepareDeck() {
		setCardDeck(new CardDeck());  //creates a new card deck
		getCardDeck().shuffleDeck();
	}

	/**
	 * Sets the mucked value of all hands to true or false
	 * @param muck True if the player mucked
	 */
	public void setPlayerHandMucks(boolean muck) {
		Table dealTable = getTable();
		int numHands = dealTable.getNumPlayerHands();
		for(int i = 0; i < numHands; i++) {
			PlayerHand pH = dealTable.getPlayerHand(i);
			pH.setMucked(muck);
		}
	}

	public void dealToHands(int numCards) {
		CardDeck deck = getCardDeck();
		Table table = getTable();
		if(deck.getNumCards() != CardDeck.DECKSIZE) {  //sanity check that it is ok to deal a new hand
			System.out.println("Cannot deal new hand right now, the deck is not full!");
			return;
		}
		int numPlayerHands = table.getNumPlayerHands();
		int totalCards = numPlayerHands * numCards;
		for(int i = 1; i <= totalCards; i++) {  //start with the hand after the button                   
			Card topCard = deck.getTopCard();
			if(topCard != null) {  //if there are still cards in the deck
				//try{ 
				//Thread.sleep(200);
				//} catch (InterruptedException e) {}
				int handPos = i % numPlayerHands;
				table.addCardToHand(topCard, handPos);
				int buttonPos = table.getButtonPosition();
			}
			else {
				System.out.println("Ran out of cards in deck - this should not have happened! =( =( =(");
				return;
			}
		}
	}


	/**
	 * TODO: not implemented in GUI yet
	 * @param ante
	 */
	public void getAntes(double ante) {
		for(int i = 0; i < getTable().getNumPlayerHands(); i++) {
			PlayerHand pHand = getTable().getPlayerHand(i);
			Player player = pHand.getPlayer();
			PotContribution pC = player.bet(ante, true);
			pHand.removeChips(ante);
			getTable().addPotContribution(pC, false);
		}		
	}
	/**
	 * 
	 * @param smallBlind
	 * @param bigBlind
	 */
	public void getBlinds(double smallBlind, double bigBlind) {
		PlayerHand smallBHand = getTable().getPlayerHand(1);
		Player sPlayer = smallBHand.getPlayer();
		PlayerHand bigBHand = getTable().getPlayerHand(2);
		Player bPlayer = bigBHand.getPlayer();
		PotContribution pCBig = bPlayer.bet(bigBlind, true);
		PotContribution pCSmall = sPlayer.bet(smallBlind, true);
		smallBHand.removeChips(smallBlind);
		bigBHand.removeChips(bigBlind);
		getTable().addPotContribution(pCSmall, false);
		getTable().addPotContribution(pCBig, false);
	}

	/**
	 * TODO: change to determine winners of each pot
	 */
	public void determineWinners() {
		List<TablePot> tPots = getTable().getPots();
		for(int i = 0; i < tPots.size(); i++) {
			List<PlayerHand> playerHandsPot = tPots.get(i).getPlayerHand();
			ArrayList<Player> winnersPot=new ArrayList<Player>();

			Collections.sort(playerHandsPot);  //sort so winners are first in list
			PlayerHand pH = playerHandsPot.get(0);
			winnersPot.add(pH.getPlayer());

			for(int j = 1; j < playerHandsPot.size(); j++) {
				PlayerHand pH2 = playerHandsPot.get(j);
				if(pH.compareTo(pH2) == 0) {  //check for equal hands (split pot) 
					winnersPot.add(pH2.getPlayer());
				}

			}


			chipsForWinner(winnersPot,tPots.get(i));
		}
	}

	/**
	 * End of round : spread the gain to the winner of the pot
	 */
	public void chipsForWinner(ArrayList<Player> Winner,TablePot tablePot){
		PokerServiceImpl pokerServerControler = PokerServiceImpl.getpokerServerControler();



		// Player who have contribute to this table pot have to split the amout
		ArrayList<Player> playerContribution=new ArrayList<Player>();
		//Fetch all the player who have contribute
		for(int j=0;j<Winner.size();j++){
			if(tablePot.getAllPlayerContributions(Winner.get(j)).size()!=0){
				playerContribution.add(Winner.get(j));
			}
		}
		// Give the chips to each winner
		for(int j=0;j<playerContribution.size();j++){
			Player winnerPot=playerContribution.get(j);
			System.out.println(winnerPot.getName() + " wins with: " + winnerPot.getPlayerHand().getRankedHand().rankToString() + "\n");
			pokerServerControler.addMessageForum(winnerPot.getName() + " wins with: " + winnerPot.getPlayerHand().getRankedHand().rankToString() + "\n");	
			winnerPot.addChips(tablePot.getTotal()/playerContribution.size());
		}
	}



	public CardDeck getCardDeck() {
		return cardDeck;
	}

	public void setCardDeck(CardDeck deck) {
		cardDeck = deck;
	}

	private void setId(String id) {
		this.id = id;
	}

	public Table getTable() {
		return table;
	}

	public void setTable(Table table) {
		this.table = table;
	}

	public abstract void update(Observable o, Object arg);

	public DealerDAO getInfo() {
		DealerDAO dealerDAO=new DealerDAO();
		dealerDAO.setCardDeck(this.getCardDeck().getInfo());
		dealerDAO.setId(this.getId());


		return dealerDAO;
	}

	public String getId() {
		return id;
	}
}
